all right everyone welcome to building a
turn-based game prototype the easiest
way before I go into the talk I would
like to give you a short setting the
stage so that you know what expect from
the next 45 minutes so that you get the
most out of this
so mostly because of the time frame we
are not going to build the next
civilization game here in here so it's
gonna be a very prototyping it's gonna
be quite code focused so I'm a
programmer so most of the concept that
we're gonna talk about are gonna be
explained in code and you do not
necessarily need a lot of VCs experience
already so I gonna introduce the concept
that we're gonna use in this talk I
gonna try to ease you all in so as long
as you're able to kind of understand
code you know they'll extend you should
be fine so what we going to do in the
next 45 minutes am I gonna give you a
short slide about my background then as
I said we gonna brush of other concepts
that we're gonna use in this talk and
then we actually gonna create something
we're gonna build a short prototype that
will be non turn based in the beginning
and we're gonna do this using ecs and
then we're gonna turn it on based
basically so if this sounds interesting
to you I'm extremely happy to like be
your host for the next 45 minutes
something about me I've been using unity
for roughly a decade now so for quite a
while I'm during the day I'm working at
Volkswagen in a department that use
unity to you actually build tools for
the engineers who develop cars so we
develop tools for the developers of cars
to make them make better cars basically
I'm also part of a very small game
studio called 3/8 games where we kind of
slow cook games in unity in our kind of
free time so it takes a while but it's
continuous progress which is nice and
little free time that is left kind of
goes into having a talk and caring about
a garden so if any of those things
sounds interesting to you or you have
any ambitions on there
feel free to just grab me after the talk
I absolutely love to share about all of
these things so turn-based games they
exists in quite a few genres the more
traditional ones are roguelikes for
example the more mainstream ones I would
say are games like civilization so
turn-based strategy games we have the
whole branch of card games like
hearthstone slay the spire that also I
usually turn-based and then we have the
topic of tactical RPGs tactical shooters
that at least offer you a way to to play
them turn-based in general and then if
you leave the digital world if you think
of board games most of the board games
that are out there are also turn-based
so if we think about a more classical
game loop in the beginning what we have
in there is that we continuously run our
game systems so we have different parts
of a game that changed the game state
and we continuously pull in events from
those things and we update the game
state accordingly which means if you
play an RPG you go to get a coffee you
might or your character might be dead
when you come back because the game kind
of kept going while you were away when
we now turn to turn based game loops we
have a very crucial difference in here
in turn-based games a frame does not
necessarily equate with a turn so we got
this separation we got two kind of
gameplay systems the first one that also
still run continuously every frame which
would be something like input or
animation or if you for example have a
weather system in your game you quite
likely also want the rain to
continuously fall down and not just move
a millimeter whenever the player turns
because that would look kind of weird
but we also have the second kind of
gameplay system that are turn-based for
example enemies making a move or the
game world changing itself and for those
system we we have a difference between
what is the frame and our update loop
and what is a turn in your gameplay
logic so looking at this we still have
this tiny loop or this fast loop that is
pulling all the engine systems if you
want so
but we do have this gameplay systems
that whoops we have this gameplay
systems that are only updated when
certain conditions are met and this is
what we're gonna gonna look at in the
next few minutes and we're gonna do this
using ECS just going to give a very
brief intro to UCS so I hope you have
heard it at least it's called entity
component system unity does few things
with this at the moment
so basically we have entities which are
kind of the new version of game object
they're just something in our game world
in a game scene and if you think of
motor behaviors we take all the data
from there and put it into components so
a component itself just is like a
container for data and we kind of build
up or entities by aggregating different
components on this and then what we have
as a third thing our systems which kind
of takes certain combinations of
components and they transform them so
what this means is we are moving from a
more traditional inheritance based
approach which means we have our class
our class has some data it has some
logic and then we inherit from this
class and it grows bigger and bigger and
bigger instead of doing this we're using
to a composition based approach so what
this means is we have very little atomic
parts like our components and then we
compose those together to form more
complex behavior um this gives us some
immediate benefits for example systems
do not longer really know what kind of
things they're operating on so you'd no
longer say you have a car and the car
should drive and you have an airplane
and they have plane to fly instead you
might have a component that gives
movement behavior and you have a system
that can operate on all those moving
behaviors so you kind of filter or
entities based on the components that
they are made of and this is interesting
for me personally because it emphasizes
something called systematic design that
I'm not going to go too deep into but
which basically means that instead of
having your logic of the game all
written out and designed by yourself you
have a lot of loose systems that
interact with each other and that can
create kind of emerging gameplay
scenario
so to give you one example Zelda a
breath of the wild the switch game is a
very good example for this because they
have the weather system they have the
lightning the fire system the weapon
system and all these things kind of
interact which with each other to allow
the player to find creative solution to
gameplay scenarios so if they interested
in this year a lot of talks in the
internet really recommend checking it
out super interesting stuff so why are
we doing this with ecs well compared to
for example last year's unite in Berlin
it is actually quite usable right now
it's fun to use it works most of the
time it gives us a high degree of
control of our game world so if you
think that most of the systems basically
can be stateless so this means whatever
happens in your world really just
depends on the components that are in
your game world which in turns mean if
you just save out all those components
you got a perfect safe game system and
whoever ever wrote a safe game system
themself in unity might appreciate those
things on the second side we get a lot
of performance and data benefits because
having those components really isolate
the data allows to do some back end
performance increases so burst compiler
and job system are all things that give
us a huge performance boost because they
can make a lot of assumptions about what
the data of the game is gonna be looked
like on an assembly level basically so
this is also good performance is also
good in games and it's gonna allow us to
use more of those cool systems that
unity is using it's the last point unity
is building on top of those steps so
even more packages will come out in the
next year so for us it's interesting to
start using ecs right now to be able to
kind of integrate those new solutions
into our game that's for the
introduction I hope you kind of feel
what we are going for and now we're
gonna start building a prototype just a
kind of brief slide we're gonna use in
unity 2019 dot-to-dot something it's a
3d template I installed the entities and
hybrid renderer package I also have
different content assets from the asset
store to make it look a bit more
tiny and there's a github repository
that is empty right now but maybe in a
week or something on upload the code and
the slights so you don't need to write
down code or anything just you know
enjoy the moment and follow along so the
prototype that we will be building is
called flying Gardner it is a great
based world so we're gonna have a 2d
grid where the entities will move on we
have two kind of actors we have the
player which is gonna be this nice blue
gardening our balloon doing gardening
things and we're gonna have non player
characters which are the evil snails
that are gonna undo gardening things
basically and the one thing that we're
gonna look at is two degree of freedom
and freedom movement so our actors
should be able to move up and down and
left and right in our game world so I
maybe when we have a lot of time we can
look at some more gameplay systems but I
guess this is gonna be the thing that we
implement over the next 35 minutes so
how do we how do we get started we want
to have our actors in the game world
which means we want to give them a
current position and we want to give
them a target position where they try to
move to the easiest way of doing this is
to create a component so when we create
an component we just inherit from AI
component data which is an interface
that is kind of the base for all
components in unity yes and in here we
defined two vector3 so the float 3 is
the new vector free from unit 2
mathematics which denotes our current
position and the target position now
when you talk about
ECS you have two different kind of
approach so you can go for pure ECS
which means you do everything in code
and instantiate your entities in code
and do not have any game objects monel
behaviors at all or there's a hybrid
approach which is as far as I got from
the keynote the approach that will be
used in the future where you were you
seen in the editor with normal game
objects and then you convert those game
object on games start to entities so
this is exactly what we're going to do
we have the blue part which is part of a
mono behavior and we implement
convert function which means that we
take this game object we do our logic
and we created the easiest part out of
this if you see in the keynote a lot of
this code is gonna be unnecessary in the
future but I didn't change the talk
because I didn't know beforehand so
gonna brush over this really quickly
what interesting that we are doing here
interesting thing that we're doing here
we're actually taking the transform
position so we're taking something from
the monobehaviour world and we're kind
of transforming it into something that
we want to have a no ACS word so what we
do here is we take the position we round
it down to a full number because we're
only interested in the grid cell that we
are in currently and then in the yellow
box we create a new extra component and
edit to our entity we're gonna not look
at this in the editor because as I said
most of this gonna be irrelevant very
soon so I'm gonna skip this when we have
our actors now what we want to do is we
want to move them around so to do this
we have the current in the target
position and we basically want to
interpolate interpolate between those
two and in ECS speech this means we have
the translation and the rotation which
are the easiest components that kind of
form what was formerly a transform and
we want to change it and to do this we
want to do it on all entities that have
a translation rotation and ecto
component because those are the three
components that we actually need to
perform this logic and the way we we do
it right now is by using a job system so
this is how it would look
right now if you build a job system we
again implement an interface and we pass
in what kind of components we are
looking for and this like I grayed out
the logic part we're basically just
looping between the positions what's
interesting here is that we are writing
logic for a single entity so we don't
really care about parallel stuff we
don't really care about race condition
because this is all things these are all
things that ECS back-end kind of gonna
take care for us so we just define what
kind of components we need we kind of
shape or query for the components and
then we have a function the execute
function that we implement that will
give us the
reference to all this components for
each entity and then to fire off this
job we have something called a system it
inherits from job system and what we do
down there is we create an instance of
our job we put an external data so in
this kind we use Delta time to animate
like it's quite useful and because we
this is constant for entities we put it
in from the outside and then just
reschedule job and ECS will take care of
the restaurants this again is kind of
invalid because the way how to write job
systems also change during the keynote
luckily it was the only job system that
I did for this talk and what we do now
is gonna be more relevant for the future
because now we can animate actors moving
around but what we are still missing to
have like the first version of a
prototype is kind of the intention to
move somewhere so what we are doing is
we're gonna create another component
called move intention that just contains
an int vector of size 2 which just give
us the x and z direction which the actor
should move and now we want to have a
system that generates cells those
randomly for our non-player actors and
what we implement here is a component
system which has an on update function
which is similar to the update of a
motor behavior and what we do in there
is we have a query with which goes to
all entities selects all entities that
has an actor component and then for each
of those entities we kind of generate a
random direction we generate a move
intention and we push this move
intention onto the entity another
interesting thing here is because we
actually add a component to the entity
we are changing the layout of the ment
of the entity so if you recall the
beginning
ECS is doing a lot of efficient growing
for us but if we change an entity doing
an update loop we create some kind of
uncertainty so all these commands that
add or remove a component will be
buffered in something called entity
command buffer which is this post update
commands so it will collect them and as
soon as we're done with the update it
will replay them and change all our
entities so again this is something
where we don't need to care about state
keeping do
parallel execution because these es will
do all of this for us and now we're
gonna actually switch to the edit or um
I have my project it's basically empty
which is not supposed to be empty that's
shitty
gonna open and explore and copy stuff
over sorry for this well this is what
you get when you do a live demo so all
the scripts that I copied in now the
stuff that we just looked in at the
presentation it's just gonna take a bit
too much time if I would like type it
out actually so what I want to do is I
gonna pull in a prefab that I created
beforehand which is like our game board
and then we're gonna pull in some
entities we have the enemies nails and
we have a player and the last thing that
we need to do is we actually need to
take our actors and assign the actor
component we just created in PowerPoint
and the unity you will tell you that you
have a you have editor script that is
looking for entity conversion but you're
actually not yet converting it so we
also add the convert to entity script so
by doing this it means when I press play
all these game objects are gonna be
converted to entities and then be
destroyed in our scene tree so if I hit
play now we see that all those entity
disappear in here and they are actually
kind of creating random movement and are
moving in the direction I mean it looks
like a very cool game already but it's
not yet turn-based so we're gonna take
this state and gonna talk about how we
actually would make this a turn-based
game so the core thing that we need is
we need a way to gather player input or
general way to kind of pass a turn and
the way we're gonna do it today is we
just gonna assume the player can make a
turn the movement and whenever the
player moves all the enemies are also
allowed to move
step and then the interesting part is
how do we actually communicate between
systems so how do we synchronize systems
in a way that we get the behavior that
we want to have and for this we're going
to look at two different variants the
first thing is going to be manual
control so we're going to do all of the
things by yourself and we look on a look
at pros and cons of this approach and
then we have a second approach spoiler
alert it might be a bit better and which
is going to be more easy se and use
components to do these things now
supposedly stuff is getting copied in
the background which is not I'm gonna
copy some things again open up a second
Explorer so what I'm copying over right
now is player component which is just an
empty component without any logic in it
just for us to kind of differentiate
between NPCs and the player character
and an input system that we're just
gonna quickly look at so basically it's
also a component system we are looking
for all entities that have this player
component we just created and then we
just check the input system if I pressed
anything from WASD and whenever I do I
gonna create a new move intention and I
gonna add it to the player ignore this
line for now it's gonna be relevant
later on so what I want to do now is I
go to my player object I also add the
player script and the last thing to do
because we are generating the move
intentions by key presses now we do no
longer want the player to receive move
intentions from the random system so I
gonna go to my random move system and we
have the query up here and what I want
to do is right now I'm just looking for
all entities that have an actor
component and I want to extend it to say
all entities that have a actor component
but do not have a player component so I
can have some kind of boolean operators
in this query
this will exclude the player and if I
hit play now lo and behold the the NPCs
are still moving around and when I press
thank you have to trust me and pressing
buttons right now the player will move
around as well
still not turn-based so back to the
drawing board
the first thing Manuel update the idea
here is pretty simple especially when
you come from the more traditional world
you've been doing something like this
implicitly so why not just take all the
turn-based system out of the normal
update loop and update them ourself
whenever we need to luckily for us there
is some ECS boilerplate code that helps
us do so so there's an attribute that we
can put on any system which is called
disable auto creation and which will
yield which will turn this system into
you not managed by UCS so UCS will not
automatically create the system for us
it will not update it for us instead we
can query for the system or self and
update it manually so what I gonna do is
file to do this I'm gonna take the move
system and I just gonna update the
system to have disable auto creation
same for the random move system because
those two systems are basically what we
want to take out of the normal update
loop because the enemies are only
allowed to do something whenever other
player has done its turn and then I have
our turn-based game loop system which
has an empty update function and what I
want to do here is I gonna write a query
and I gonna look for entities that have
the player component and the move
intention so this means that this query
will only ever find anything whenever we
press the key and the input system gave
a move intention to our player
and what we going to do in here is we're
gonna go to world which is kind of the
thing that all the entities in system
live in and we're gonna say get or
create system run a move system and
update this
so this get or create system gives us a
reference to the move system a random
move system and if there is no random
move system right now it will create one
and we want to do this for the move
system itself so just brief reminder
random move system creates a random
direction on each actor component that
is not a player and the move system just
takes all this move intentions and
changed the target position accordingly
so if we go back to the edit or we
should see that nothing is moving well
that's good and if I press and button
you see that when the player moves the
enemy moves at well as well I can can
play it like a real-time game if I press
fast enough but it is kind of turn-based
now so why don't we just stop here we
have very fine control about what's
happening so we can specify the order in
which the system's get updated it has a
pretty low footprint because we only
need to add this attribute to a system
to take it out of the loop um but it
doesn't really scale scale well so if
you think about a situation where you
may be published your game and you want
to allow other people to mod gameplay
systems for example they need to have
access to your turn-based game because
they need to later on include the system
in the game loop also if you have like
bit more complex systems and we have
right now so we just say whenever the
player has a move intention you pass a
turn but what happens if we do more
actions and just moving around like this
things pretty easily gets complicated
because you have a lot of dependencies
between the systems which is something
that we would not like to have so we're
gonna look at another approach which is
a bit more complex but all
so scales way better as we gonna see in
a second and gonna come with some
special perks that we're going to look
at if we have the time so the idea is to
use components without any data just
like a flag to communicate between the
systems and the idea here is that every
player actor in a scene gets a flag that
says okay you are awaiting an action so
we have this component on the player and
then when we use our input system we
actually consume this component so the
input system gives the players the
intention to move somewhere and it takes
away this flag that the player is
waiting for something and then in our
turn-based system instead of kind of
waiting or instead of calling the
system's themselves like we do right now
we hand out like a card to the actors
which say ok you allowed to do something
for this one frame so at some point the
player is going to do something and then
we're going to allow the actors to
change the game state for one frame and
if this frame is done so all the systems
have ticked we're just gonna take the
card back and sorry for copying all the
stuff but it was supposed to work better
I just gonna quickly remove the thing
that we had before stop play mode and
I'm gonna look at a chunk of code so the
first thing that I'm gonna do is gonna
remove the attributes because if I
forget everything will fail and we want
the system's to be updated by UCS so
instead of taking the out of the normal
loop we just gonna ecs let up let
ezs update the systems and we're gonna
put a check into the systems to see if
they are allowed to move those are the
two flags so we have the right action
flag which will be on the player saying
that the player is still waiting to
receive input and we have the ready to
handle flag which says that an actor is
allowed to do something we will in a
second build or turn-based game loop but
before we will prepare our systems the
first thing that we're going to do in
the player component we have this
convert function
we take the game object we destroy the
game object and we add a player
component and additionally we're gonna
add an a weight action flag so we're
gonna when we create the player entity
we're gonna put it into the state of
waiting for action immediately and we're
gonna go to the input system and here
when we put a move intention onto the
player in the same way and we're gonna
remove this flag so as soon as we give
the player intention to move we're going
to remove this flag that it's still
waiting for something to happen and I
just gonna edit down here which means
that the input system will only run off
players that still await for an action
so if I have multiple players which is
something that will become possible in a
few minutes I will make sure that only
the players can receive input that
haven't so far in this frame and now we
go to our turn-based systems and in here
in the move system we can just say that
we are no longer running on all entities
that have an actor component but instead
we gonna filter and say ok you are only
allowed to run if you have this ready to
handle flag same goes for the Move
system I just gonna edit in here so this
systems will get called on update every
frame but this query will actually make
sure that they are only doing something
in the update loop when they have this
flag so what we now still need to do is
to build our turn-based engine to kind
of hand out those things and we're gonna
do a neat trick here so I just gonna
create a variable and we're gonna have
query which looks for all entities that
have an a weight action flag and instead
of using for each to execute a lambda
function on it we just gonna get the
entity query object from ecs and we're
gonna calculate how many entities are in
there so basically what we are looking
here is for all the entities that are
still awaiting action and then we count
how many there are
and then we can do something like with
waiting it is equal to zero so if all
the actors that await action have
actually received an action we can go
and go to all the actors in a scene now
we want to change the entities are going
to execute a lambda and we're gonna say
when you're done with your update please
add a component which is the ready to
handle flag on the entity so as soon as
all the player have received the action
we gonna give this token out to all the
other entities and before them I want to
reset the players so we're gonna
additionally go to all the player
component entities and give them an a
wait action flag and if you think if you
go back to this loop the one thing that
we need to do still is after we've
passed one term we need to need to take
this token back basically so that the
systems are not allowed to continuously
execute but we only want them to to
execute one frame so what I'm gonna do
up here is for every entity that had
already and ready to handle flag I gonna
remove it again so this means basically
there will be one full frame where this
ready to handle flag exists on enter
team and now we get the magic code line
because for some reason this won't work
if you include a query which is queries
anything without doing anything it does
work so please don't ask me why
something that I figured out late at
night and we're just gonna take it as a
best practice for UCS I assume that it's
gonna be kind of disappear at some point
all right I hope I didn't forget
anything let me just quickly check my
sheet list looks good so far
so if we hit play again assumption is
nothing is moving good so far and if I
press the player the MPC yes so
sometimes i generate non-valid moves
which would bring you out of the game
field so if a snare around here doesn't
move okay for me so it works nice and so
what do we have for what properties do
we have here so it scales nicely because
the turn-based system itself does know
nothing about the system that consumed
this avoid action flag it doesn't know
nothing about the system that work on
this ready to handle flag so it kind of
scales for all the systems that we're
going to introduce later um we are able
to kind of front load some effort so I
could write a base class for systems
that should be turn-based so do all this
looking for certain tech and stuff and
later on I don't need to care about it
because we are counting how many players
are waiting for input we do have
multiplayer and I gonna keep talking but
faster so maybe we're gonna hack in some
multiplayer here and on the down side we
have more complexity so we need to kind
of write more code in our systems we
beat we need to be more like we need to
think more about how we do our game
logic and if you paid close attention
you saw that the enemies did not move on
the first frame so when I move the
player the first time the enemies
actually did not move which is because
the order of our systems now is relevant
I'm gonna give a quick look at the
entity debugger which gives us insight
into the whole thing that is running on
the ECS side and if you see is that the
move system updates before the render
move system so what is happening here is
we do our update loop at some point we
have the turn based loop which hence
ours was token then we go update loop
then the move system triggers and there
is no move intention because it has not
yet been created so only the system
after creates a move system or the move
intention
and then the next frame everything works
like a charm so there are different ways
to work around this maybe you're gonna
touch some of those but in generally
it's a downside that you need to kind of
think about if you have any order in
your system that is relevant for a
gameplay logic so this is like a very
bare bone prototype you have the
turn-based gameplay you have an idea how
to extend it but we don't have any
gameplay so next step obviously would be
to think about what is necessary to win
the game how can the player lose the
game how do all this game thingies come
in another idea would be to talk about
alternative turn modes so right now we
have the system one player action means
turn is past players have all done the
turn and enemies are doing the turn you
could also have something like a timed
move so that the player has a certain
amount of time to do actions and then
the world turns or you can have
something like in board games where the
player can do as many actions as
possible with given resource and then
manually enter turn um you could also go
ahead and take all this nice UCS base
packages and put this into the game so
we have the physics system which is
deterministic stateless allows us to all
to do all crazy things with multiplayer
we have this life play life link thing
that we can implement in here so
basically this prototype gives you a
good foundation to kind of extend on all
the stuff that is unity working on right
now and I'm gonna skip recap for now
instead we're gonna try to do to turn
this whole thing in a local multiplayer
game and I would offer to like after the
session be outside for a few minutes
half an hour to ask all your questions
so if you think about it we are counting
the players so in theory if I just add
another player and give it player actor
and convert entity script and hit play
now it is not super interesting because
both players will just kind of move
simultaneously because in our input
system we do not differentiate between
players
so what we could do in here and this is
not really practiced so I hope that it
will work out but if I just give the
player compound the player ID and I will
this will also put it into the
monobehaviour so that I can edit it from
the editor and then I need to change
this to not only put in an empty
component instead I want to do a new
[Music]
player component and I want to say that
the player ID equals to the thing that I
just said in the edit or yes and now I
can go to my input system and I'm just
gonna take out the player component in
here and put it into here the change
means that instead of just seeing if the
component exists I'm actually gonna get
a reference to this this is also some
performance implications because burst
is clever in the job system is clever
enough to kind of differentiate between
jobs that can run in parallel because
they're not reading and writing on the
same component and jobs that need to run
back-to-back because they're gonna
access the same component so I'm just
gonna check if my player ID equals zero
if so I gonna do the same thing that did
it before and if not I just gonna look
for a different set of keys so I'm gonna
go for arrow and
right arrow like this and I just gonna
go into the edit or and we can as soon
as we have the scripts we can take one
player that keeps a player ID zero and
the second player gonna have the player
ID one and if I hit play I gonna press W
for the first player nothing happens
because we are still have one player
waiting for input and if I now press an
arrow key you see that both players
actually moves feels a bit clunky but in
theory you have something like local
multiplayer play which is awesome
because we didn't conceptualize our game
in the beginning two people two player
games and the way that it's so easily
extendable it's always something that
baffles me we can quickly fix the
problem with the turning of the enemies
again there's an attribute so we can do
something like update before type of
move system so this is just like random
stuff that we could quickly use to
extend the whole thing so this means
that the UCS update loop is going to
take care that the random move system is
always called somewhere before a move
system so it will sort it internally
which should kind of get rid of this
problem and the last thing that is kind
of nagging me is that I press a key for
the first player but I don't see any
immediate response so this feels very
unintuitive so I gonna change this for
not only look for ready to handle flag
but to look for a ready to handle flag
or a player component so this means our
players have kind of special role they
will move as soon as a receiving a move
in tension and if I play it now I should
see that as soon as I press W the first
time I move as soon as press something
else the second player moves and now we
have our enemies moving the first turn
as well but only if both player has
moved have moved all right so let's
quickly recap what we did so we looked
at some easiest building blocks we
looked at how we
could connect these the monobehaviour
editor word to ECS we talked a bit about
a turn-based game loop we talked about
how player action could trigger changes
in our game world and then we build
different variants of a turn-based game
system which gives you kind of a
foundation to kind of extend onto
prototype away that's from my site thank
you all for staying with me I know
that's a lot of digestion right here
we have four minutes left so I would
again say that I pack up my stuff and if
you have any questions we can meet
outside and I'm happy to answer them we
also have some three out game stickers
around so if you're a sticker person you
don't have to ask a question you can
just grab a few stickers and thank you
for spending your time here
[Applause]
[Music]